/*****************************************************************************
 * ADT Example Program:		ADT_L1_A429_ex_rxtx1.c
 *
 * Copyright (c) 2008, Alta Data Technologies LLC (ADT), All Rights Reserved.
 * Use of this software is subject to the ADT Software License (latest
 * revision), US Government or local laws and the ADT Terms and Conditions
 * of Sale (latest revision).
 *
 * Description:
 *		This program demonstrates setting up an A429 device with RX channel 1
 *		and TX channel 1.  RX channel 1 can see the	labels sent by TX channel 1.
 *
 *****************************************************************************/
#include <stdio.h>
#include "ADT_L1.h"

/* The DEVICE ID is a 32-bit value that identifies the following:
 *		bits 28-31 = Backplane Type (0 = Simulated, 1 = PCI)
 *		bits 20-27 = Board Type (0x10 = SIM-A429, 0x11 = TEST-A429, 0x12 = PMC-A4293, 0x13 = PC104P-A429, 0x14 = PCI-A429)
 *		bits 16-19 = Board Number (0 to 15)
 *      bits 8-15 = Channel Type (0x10 = 1553, 0x20 = A429)
 *		bits 0-7 = Channel/Device Number (0 to 255)
 *
 */
#define DEVID (ADT_PRODUCT_PMCA429 | ADT_DEVID_BOARDNUM_01 | ADT_DEVID_CHANNELTYPE_A429 | ADT_DEVID_BANK_01)

int A429_test() 
{
	ADT_L0_UINT32 status, l0Version, l1Version, chanConfig;
	ADT_L0_UINT16 peVersion;

    ADT_L0_UINT32 numRXPs, i;
	ADT_L1_A429_TXCB myTXCB;
	ADT_L1_A429_TXP myTXP;
	ADT_L1_A429_RXP myRXP_buffer[10];
	char c;
	char strIn[32];
	ADT_L0_UINT32 s1, s2, s3, s4, c1, c2, c3, c4;
	ADT_L0_UINT32 portnum, transactions, retries, failures;


	printf("********** ADT L1 API Example Program **********\n\n");


	printf("Initializing Driver and Memory Management . . . ");
	status = ADT_L1_A429_InitDefault(DEVID, 10);
	/* NOTE ON A429 DEVICE INITIALIZATION FUNCTIONS:
	 *	The recommended initialization method is ADT_L1_A429_InitDefault.  This function initializes the A429 device, 
	 *	performs a memory test (can take a few seconds), and allocates the interrupt queue.
	 *
	 *  If the application is exited abnormally (and the ADT_L1_CloseDevice was not called), then the next time the
	 *  device is initialized you may see status/error 1017 (ADT_ERR_DEVICEINUSE).  This is used to prevent two applications
	 *  from initializing the same device.  On an abnormal exit the board can be left in a "IN USE" state.  This
	 *  state can be overridden using the ADT_L1_A429_InitDefault_ExtendedOptions function.  This function can be
	 *  used to force initialization when the device is in use with the option ADT_L1_API_DEVICEINIT_FORCEINIT.
	 *  This function can also be used to skip the initialization memory test with the option ADT_L1_API_DEVICEINIT_NOMEMTEST.
	 *  See the AltaAPI Users Manual for more details on this function.  Here is an example of the initialization call
	 *  using these options:
	 *
	 *	printf("Initializing Device with Reset and No Mem Test. . . ");
	 *	status = ADT_L1_A429_InitDefault_ExtendedOptions(DEVID, 10, ADT_L1_API_DEVICEINIT_FORCEINIT |
	 *																ADT_L1_API_DEVICEINIT_NOMEMTEST |
	 *																ADT_L1_API_DEVICEINIT_ROOTPERESET);
	 */
	if (status != ADT_SUCCESS) printf("ERROR %d on ADT_L1_A429_InitDefault\n", status);
	else
	{
		printf("Success.\n\n");

		printf("Checking Protocol Engine (PE) and API versions . . . ");
		status = ADT_L1_GetVersionInfo(DEVID, &peVersion, &l0Version, &l1Version);
		if (status == ADT_SUCCESS) {
			printf("Success.\n");
			printf("   PE version = %04X\n", peVersion);
			printf("   L0 API version = %d.%d.%d.%d\n", (l0Version & 0xFF000000) >> 24, 
				(l0Version & 0x00FF0000) >> 16, (l0Version & 0x0000FF00) >> 8, l0Version & 0x000000FF);
			printf("   L1 API version = %d.%d.%d.%d\n\n", (l1Version & 0xFF000000) >> 24, 
				(l1Version & 0x00FF0000) >> 16, (l1Version & 0x0000FF00) >> 8, l1Version & 0x000000FF);
		}
		else printf("FAILURE - Error = %d\n\n", status);

		printf("Checking Channel Configuration . . . ");
		status = ADT_L1_A429_GetConfig(DEVID, &chanConfig);
		if (status == ADT_SUCCESS) {
			printf("Success.\n");
			printf("   Channel Configuration = %08X\n\n", chanConfig);
		}
		else printf("FAILURE - Error = %d\n\n", status);

		/* Setup RX Channel 1 */
		printf("Initializing RX Channel 1 . . . ");
		status = ADT_L1_A429_RX_Channel_Init(DEVID, 0, 100000, 100, 0);
		if (status != ADT_SUCCESS) printf("ERROR %d on ADT_L1_A429_RX_Channel_Init\n", status);
		else
		{
			printf("Success\n\n");

			/* Start RX Channel 1 */
			printf("Starting RX Channel 1 . . . ");
			status = ADT_L1_A429_RX_Channel_Start(DEVID, 0);
			if (status != ADT_SUCCESS) printf("ERROR %d on ADT_L1_A429_RX_Channel_Start\n", status);
			else
			{
				printf("Success\n\n");

				/* Setup TX Channel 1 */
				printf("Initializing TX Channel 2 . . . ");
				status = ADT_L1_A429_TX_Channel_Init(DEVID, 1, 100000, 10);
				if (status != ADT_SUCCESS) printf("ERROR %d on ADT_L1_A429_TX_Channel_Init\n", status);
				else
				{
					printf("Success\n\n");

					printf("Allocating TXCB and TXP . . . ");
					status = ADT_L1_A429_TX_Channel_CB_TXPAllocate(DEVID, 1, 0, 1);
					if (status != ADT_SUCCESS) printf("ERROR %d on ADT_L1_A429_TX_Channel_CB_TXPAllocate\n", status);
					else
					{
						printf("Success\n\n");

						/* NOTE:
						 * If you have a TX list with labels sent at different rates, you should add the fastest
						 * labels to the list FIRST, followed by slower labels.  This allows the firmware to 
						 * process faster labels before slower labels and thus keep up with label timing.  If a
						 * fast label follows a slower label, the firmware can be delayed in transmitting the
						 * faster label, resulting in timing jitter.
						 */

						printf("Writing TXCB . . . ");
						memset(&myTXCB, 0, sizeof(myTXCB));
						myTXCB.NextTxcbNum = ADT_L1_A429_TXCB_NO_NEXT_TXCB;  /* Do NOT point TXCB to itself or to first TXCB - mark last one with msg number 0xFFFFFFFF */
						myTXCB.Control = 0;
						myTXCB.TxPeriod500us = 200;  /* 100ms period (10Hz), with 500us LSB = 200 */
						status = ADT_L1_A429_TX_Channel_CB_Write(DEVID, 1, 0, &myTXCB);
						if (status != ADT_SUCCESS) printf("ERROR %d on ADT_L1_A429_TX_Channel_CB_Write\n", status);
						else
						{
							printf("Success\n\n");

							printf("Writing TXP . . . ");
							myTXP.Control = ADT_L1_A429_TXP_CONTROL_PARITYON | ADT_L1_A429_TXP_CONTROL_PARITYODD;
							myTXP.Delay = 400;  /* A429 minimum gap is 4 bit-times, at 100KHz, this is 40us.  At 100ns LSB, this is 400 */
							myTXP.Data = 0x12345678;
							status = ADT_L1_A429_TX_Channel_CB_TXPWrite(DEVID, 1, 0, 0, &myTXP);
							if (status != ADT_SUCCESS) printf("ERROR %d on ADT_L1_A429_TX_Channel_CB_TXPWrite\n", status);
							else
							{
								printf("Success\n\n");

								printf("Starting TX Channel 1 . . . ");
								status = ADT_L1_A429_TX_Channel_Start(DEVID, 1, 0);
								if (status != ADT_SUCCESS) printf("ERROR %d on ADT_L1_A429_TX_Channel_Start\n", status);
								else
								{
									printf("Success\n\n");

									c = ' ';
									while (c != 'Q') {
										printf("\nInput Q to Quit, X to stop TX, S to start TX, or R to read RX CH1 data ");
										scanf("%c", &c);
										if (c == 'X') {
											printf("Stopping TX Channel 2 . . . ");
											status = ADT_L1_A429_TX_Channel_Stop(DEVID, 1);
											if (status != ADT_SUCCESS) printf("ERROR %d on ADT_L1_A429_TX_Channel_Stop\n", status);
											else printf("Success.\n");
										}
										else if (c == 'S') {
											printf("Starting TX Channel 2 . . . ");
											status = ADT_L1_A429_TX_Channel_Start(DEVID, 1, 0);
											if (status != ADT_SUCCESS) printf("ERROR %d on ADT_L1_A429_TX_Channel_Start\n", status);
											else printf("Success.\n");
											
											myTXP.Data = myTXP.Data + 1;
											status = ADT_L1_A429_TX_Channel_CB_TXPWrite(DEVID, 1, 0, 0, &myTXP);
										}
										else if (c == 'R') {
											printf("Reading RX Channel 1 data . . . ");
											status = ADT_L1_A429_RX_Channel_ReadNewRxPs(DEVID, 0, 10, &numRXPs, myRXP_buffer);
											if (status != ADT_SUCCESS) printf("ERROR %d on ADT_L1_A429_RX_Channel_ReadNewRxPs\n", status);
											else
											{
												printf("Success\n");

												if (numRXPs == 0) {
													printf("No Labels Received.\n");
												}
												else {
													for (i=0; i<numRXPs; i++)
													{
														
														printf("RX CH1: Label Received: %08X\n", myRXP_buffer[i].Data);
													}
												}
											}
										}
									}

									printf("Stopping TX Channel 1 . . . ");
									status = ADT_L1_A429_TX_Channel_Stop(DEVID, 0);
									if (status != ADT_SUCCESS) printf("ERROR %d on ADT_L1_A429_TX_Channel_Stop\n", status);
									else
									{
										printf("Success\n\n");
									}
								}
							}
						}
					}

					printf("Closing TX Channel 1 . . . ");
					status = ADT_L1_A429_TX_Channel_Close(DEVID, 0);
					if (status != ADT_SUCCESS) printf("ERROR %d on ADT_L1_A429_TX_Channel_Close\n", status);
					else
					{
						printf("Success\n\n");
					}
				}
			}

			printf("Closing RX Channel 1 . . . ");
			status = ADT_L1_A429_RX_Channel_Close(DEVID, 0);
			if (status != ADT_SUCCESS) printf("ERROR %d on ADT_L1_A429_RX_Channel_Close\n", status);
			else
			{
				printf("Success\n\n");
			}
		}

		printf("Closing Device . . . ");
	    status = ADT_L1_CloseDevice(DEVID);
		if (status != ADT_SUCCESS) printf("ERROR %d on ADT_L1_CloseDevice\n", status);
		else
		{
			printf("Success\n\n");
		}
	}  

	return(0);
}